package com.example.springboot.config.interceptors;

import com.example.springboot.config.anotation.requstlimit.RequestLimit;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Author:ChenZhangKun
 * @Date: 2021/7/29 11:00
 */
@Component
@Slf4j
public class RequestLimitInterceptor implements HandlerInterceptor {
    @Autowired
    private StringRedisTemplate redisTemplate;
    private static final String SUFFIX = "/API";
    ScheduledExecutorService scheduledExecutorService = null;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 拿到请求方法
        if (handler instanceof HandlerMethod) {
            // 强转
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            // 拿到注解
            if (handlerMethod.getMethod().isAnnotationPresent(RequestLimit.class)) {
                // 拿到注解
                RequestLimit requestLimit = handlerMethod.getMethod().getAnnotation(RequestLimit.class);
                // 拿到限制时间
                int count = requestLimit.count();
                int seconds = requestLimit.seconds();
                // key
                String key = request.getRequestURI() + SUFFIX;
                // 拿到次数
                Object object = redisTemplate.opsForValue().get(key);
                if (object == null) {
                    // 第一次访问，放行
                    redisTemplate.opsForValue().set(key, "1");
                    // 检查线程池是否开启
                    if (scheduledExecutorService==null||scheduledExecutorService.isShutdown()){
                        doScheduled(seconds, key);
                    }
                    return true;
                } else {
                    // 强转
                    String i = (String) object;
                    log.info("检测到目前ip对接口={}已经访问的次数{}", request.getServletPath(), i);
                    // 设置次数
                    if (Integer.parseInt(i) >= count) {
                        returnData(response);
                        return false;
                    } else {
                        // 执行加一
                        redisTemplate.opsForValue().increment(key);
                    }
                }
            }
        }
        return true;
    }

    private void doScheduled(int seconds, String key) {

        AtomicInteger atomicInteger = new AtomicInteger();
        scheduledExecutorService = Executors.newScheduledThreadPool(1);
        scheduledExecutorService.scheduleAtFixedRate(() -> {
            if (redisTemplate.hasKey(key)) {
                redisTemplate.delete(key);
                // 计数器重置
                atomicInteger.set(0);
                log.info("【删除key{},时间{}】", key, new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()));
            } else {
                log.info("【没有检测到key={},时间：{}】", key, new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()));
                if (atomicInteger.getAndIncrement() > 3) {
                    // 3次没有删除到，结束线程
                    log.info("【3次没有删除到，结束线程】");
                    // 关闭线程池
                    scheduledExecutorService.shutdown();
                }
            }
        }, 0, seconds, TimeUnit.SECONDS);
    }

    /**
     * 处理返回请求的
     *
     * @param response
     * @throws IOException
     */
    private void returnData(HttpServletResponse response) throws IOException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        ObjectMapper objectMapper = new ObjectMapper();
        response.getWriter().println(objectMapper.writeValueAsString("请求过于频繁请稍后再试"));
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}
